package org.hawk.gwt.ppc.parser.impl;

import org.hawk.gwt.ppc.parser.Descriptor;
import org.hawk.gwt.ppc.parser.DescriptorVisitor;
import org.hawk.gwt.ppc.parser.JavaKeywords;
import org.hawk.gwt.ppc.parser.PackageDescriptor;
import org.hawk.gwt.ppc.parser.PreprocessorParseException;
import org.hawk.gwt.ppc.parser.Token;
import org.hawk.gwt.ppc.utils.PreprocessorException;

import static org.hawk.gwt.ppc.parser.impl.DescriptorParserUtils.*;

/**
 * Parses package declaration.
 * 
 * @author alex.bereznevatiy@gmail.com
 */
final class PackageDescriptorParser implements DescriptorParser {

	/**
	 * @return default package descriptor
	 */
	static PackageDescriptor createDefaultPackage() {
		return new PackageDescriptorImpl(null, null);
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.parser.impl.DescriptorParser#accepts(org.hawk.gwt.ppc.parser.Token)
	 */
	public boolean accepts(Token token) {
		return token.equalsTo(JavaKeywords.PACKAGE);
	}

	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.parser.impl.DescriptorParser#parse(org.hawk.gwt.ppc.parser.impl.TokenBasedJavaParser, org.hawk.gwt.ppc.parser.impl.Tokenizer)
	 */
	public Descriptor parse(TokenBasedJavaParser parser, TokenSource tokenizer, Object...params)
			throws PreprocessorException {
		StringBuilder packageName = new StringBuilder();
		
		boolean dot = false;
		Token first = tokenizer.current();
		
		Token current;
		while (tokenizer.hasNext() && !(current = tokenizer.next()).equalsTo(';')) {
			
			if ((dot && !current.equalsTo('.')) ||
				(!dot && !current.isWord())) {
				throw new PreprocessorParseException("Wrong token", tokenizer.current());
			}
			dot = !dot;
			current.writeTo(packageName);
		}
		
		if (!tokenizer.current().equalsTo(';') || !dot) {
			throw new PreprocessorParseException(tokenizer.current());
		}
		
		PackageDescriptorImpl result = new PackageDescriptorImpl(first, tokenizer.current());
		result.packageName = packageName.toString();
		
		lookupNext(tokenizer, true);
		 
		return result;
	}

	/**
	 * 
	 * @author alex.bereznevatiy@gmail.com
	 *
	 */
	private static class PackageDescriptorImpl extends AbstractDescriptor implements PackageDescriptor {
		private String packageName;

		private PackageDescriptorImpl(Token firstToken, Token lastToken){
			super(firstToken, lastToken);
		}
		
		/*
		 * (non-Javadoc)
		 * @see org.hawk.gwt.ppc.parser.PackageDescriptor#getPackageName()
		 */
		public String getPackageName() {
			return packageName == null ? "" : packageName;
		}
		
		/*
		 * (non-Javadoc)
		 * @see org.hawk.gwt.ppc.parser.Descriptor#visit(org.hawk.gwt.ppc.parser.DescriptorVisitor)
		 */
		public void visit(DescriptorVisitor visitor) throws PreprocessorException {
			visitor.visit(this);
		}
	}
}
